﻿using Devil;
using GameToolkit.ContentProvider;
using LitJson;
using System.Collections.Generic;
using UnityEngine;

namespace GameToolkit
{

    [System.Serializable]
    public class TablesForEditor
    {
        public class Data : TableBase
        {
            JsonData mContent;

            public JsonData this[string key] { get { return mContent[key]; } }
            public JsonData Content => mContent;

            public string GetPropertyTitle(TableReferenceAttribute tref, bool singleLine)
            {
                string str;
                var txt = mContent[tref.TextReference];
                if (txt != null)
                {
                    str = $"[{DataId}] {txt}";
                    int n = singleLine ? str.IndexOf('\n') : -1;
                    if (n > 0)
                        str = ParallelUtils.Concat(str.Substring(0, n), "...");
                }
                else
                {
                    txt = mContent[tref.TableProperty];
                    if (txt != null)
                    {
                        str = $"[{DataId}] {txt}";
                        int n = singleLine ? str.IndexOf('\n') : -1;
                        if (n > 0)
                            str = ParallelUtils.Concat(str.Substring(0, n), "...");
                    }
                    else
                    {
                        str = $"[{DataId}]";
                    }
                }
                return str;
            }

            public string GetPropertyTitle(string property, bool includeId = false, bool singleLine = true)
            {
                JsonData txt = null;
                if (!property.EndsWith(".ref"))
                {
                    txt = mContent[$"{property}.ref"];
                }
                if (txt == null)
                {
                    txt = mContent[property];
                }
                string str;
                if (txt != null)
                {
                    str = includeId ? $"[{DataId}] {txt}" : txt.ToString();
                    var n = singleLine ? str.IndexOf('\n') : -1;
                    if (n > 0)
                        str = ParallelUtils.Concat(str.Substring(0, n), "...");
                }
                else
                {
                    str = $"[{DataId}]";
                }

                return str;
            }

            protected override void OnDeserialize(JsonData data)
            {
                base.OnDeserialize(data);
                mContent = data;
                Dictionary<string, string> refs = new Dictionary<string, string>();
                foreach (var k in data.Keys)
                {
                    var v = data[k];
                    if (v != null && v.GetJsonType() == JsonType.Long && k != "id")
                    {
                        var txt = new TextReference((int)v).ToString(sTexts);// TextRes.GetText((int)v, null);
                        if (!string.IsNullOrEmpty(txt))
                            refs[$"{k}.ref"] = txt;
                    }
                }
                foreach (var kv in refs)
                {
                    data[kv.Key] = kv.Value;
                }
            }
        }

        static ParallelDispatcher.Handler sJob;
        static TableSet<TextRes> sTexts = new TableSet<TextRes>(true);
        static Dictionary<string, Table> sTables = new Dictionary<string, Table>();

        class Table
        {
            internal readonly TableSet<Data> mTable;
            internal readonly HashSet<System.Action<TableSet<Data>>> mModifiers;

            internal Table()
            {
                mTable = new TableSet<Data>();
                mModifiers = new HashSet<System.Action<TableSet<Data>>>();
            }
        }

#if UNITY_EDITOR
        [UnityEditor.MenuItem("Game Toolkit/数据/重新加载数据表")]
#endif
        [InitializeOnLoadMethodParallel]
        static void ReloadTables()
        {
            sTexts.Dispose();
            sTexts = new TableSet<TextRes>(true);
            sJob = ParallelUtils.ScheduleParallel<Table>(ReloadTable, sTables.Values, sJob);
        }

        static void ReloadTable(Table tab)
        {
            var file = tab.mTable.TableName;
            LoadTable(file, tab);
        }

        static void LoadTable(string file, Table tab)
        {
            try
            {
                var folder = NativeFileSystem.GetFolderName(file);
                while (true)
                {
                    var txtfile = NativeFileSystem.Combine(folder, "Texts/cn/Texts.txt");
                    if (NativeFileSystem.HasFile(txtfile))
                    {
                        var txt = NativeFileSystem.ReadAllText(txtfile);
                        if (!string.IsNullOrEmpty(txt))
                            sTexts.LoadDatas(txtfile, JsonMapper.ToObject(txt));
                        break;
                    }
                    else
                    {
                        var f = NativeFileSystem.GetFolderName(folder);
                        if (f == folder)
                            break;
                        else
                            folder = f;
                    }
                }
                var tabfile = NativeFileSystem.ReadAllText(file);
                if (!string.IsNullOrEmpty(tabfile))
                {
                    var content = JsonMapper.ToObject(tabfile);
                    tab.mTable.LoadDatas(file, content);
                    foreach(var modifier in tab.mModifiers)
                    {
                        modifier?.Invoke(tab.mTable);
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
        }

        public static TableSet<Data> RequestTable(string table)
        {
            if (string.IsNullOrEmpty(table))
                return null;
            var file = table.ToLower();
            lock (sTables)
            {
                Table tab;
                if (!sTables.TryGetValue(file, out tab))
                {
                    tab = new Table();
                    sTables[file] = tab;
                    LoadTable(file, tab);
                }
                return tab.mTable;
            }
        }

        public static Data RequestTableData(string table, int id)
        {
            var tab = RequestTable(table);
            if (tab == null)
                return null;
            else
                return tab[id];
        }
    }
}
